module oderogue.tcod.console;

import std.string;

import derelict.tcod.libtcod;

import oderogue.tcod.Key;
import oderogue.tcod.Color;

public final class ConsoleManager
{
	private static Console mainConsole;
	
	// Prevent instantiation
	private this() {}
	
	/**
	 * Creates a new main window as the main console. Once this function has been called, you can access 
	 * the main console by calling ConsoleManager#getMainConsole.
	 *
	 * Params:
	 *	width = the width of the console in characters. The default width in libtcod is 8.
	 *	height = the height of the console in characters. The default height in libtcod is 8.
	 *	title = The title of the window.
	 *	fullScreen = Flag indicating wether the window starts in fullscreen mode or not.
	 *
	 * Returns: The created main console
	 */
	public static Console createMainConsole(int width, int height, string title = "", bool fullScreen = false)
	{
		TCOD_console_init_root(width, height, toStringz(title), fullScreen);
		mainConsole = new Console(null);
		return mainConsole;
	}
	
	/**
	 * Creates a new offscreen console with the given size.
	 *
	 * Params:
	 *	width = The width of the console in characters.
	 *	height = The height of the console in characters.
	 *	 
	 * Returns: The created offscreen console.	 
	 */
	public static Console createOffscreenConsole(int width, int height)
	{
		return new Console(TCOD_console_new(width, height));
	}
	
	public static Console getMainConsole()
	{
		return mainConsole;
	}
}

public final class Console
{
	private TCOD_console_t console;
	
	public alias console this;
	
	private this(TCOD_console_t console)
	{
		this.console = console;
	}
	
	public ~this()
	{
		if (console)
		{
			TCOD_console_delete(console);
		}
	}
	
	/**
	 * Once the root console is initialized, you can use one of the printing functions to change the background colors, 
	 * the foreground colors or the ASCII characters on the console.
	 * Once you've finished rendering the root console, you have to actually apply the updates to the screen with this 
	 * function.
	 */
	public void flush()
	{
		if (!console)
		{
			TCOD_console_flush();
		}
	}
	
	/**
	 * This function modifies all cells of a console:
	 * - set the cell's background color to the console default background color
	 * - set the cell's foreground color to the console default foreground color
	 * - set the cell's ASCII code to 32 (space)
	 */
	public void clear()
	{
		TCOD_console_clear(console);
	}
	
	/**
	 * This function waits for the user to press a key. It returns the code of the key pressed as well as 
	 * the corresponding character. If the flush parameter is true, every pending keypress event is discarded, 
	 * then the function wait for a new keypress.
     * If flush is false, the function waits only if there are no pending keypress events, else it returns the first 
	 * event in the keyboard buffer.
	 */
	public Key waitForKeyPress(bool flush = false)
	{
		return Key(TCOD_console_wait_for_keypress(flush));
	}
	
	/**
	 * This function changes the default background color for a console. The default background color is used by 
	 * several drawing functions like clear, putChar, ...
	 */
	public void setDefaultBackgroundColor(Color color)
	{
		TCOD_console_set_background_color(console, color.data);
	}
	
	/**
	 * This function changes the default foreground color for a console. The default foreground color is used by 
	 * several drawing functions like clear, putChar, ...
	 */
	public void setDefaultForegroundColor(Color color)
	{
		TCOD_console_set_foreground_color(console, color.data);
	}
	
	/**
	 * This function modifies every property of a cell:
	 * - update the cell's background color according to the console default background color (see TCOD_bkgnd_flag_t).
	 * - set the cell's foreground color to the console default foreground color
	 * - set the cell's ASCII code to c
	 */
	public void putChar(int x, int y, int c, TCOD_bkgnd_flag_t flag = TCOD_BKGND_SET)
	{
		TCOD_console_put_char(console, x, y, c, flag);
	}
	
	/**
	 * This function modifies every property of a cell:
	 * - set the cell's background color to back.
	 * - set the cell's foreground color to fore.
	 * - set the cell's ASCII code to c
	 */
	public void putCharEx(int x, int y, int c, Color fore, Color back)
	{
		TCOD_console_put_char_ex(console, x, y, c, fore.data, back.data);
	}
	
	/**
	 * This function modifies the background color of a cell, leaving other properties (foreground color and 
	 * ASCII code) unchanged.
	 */
	public void setBackgroundColor(int x, int y, Color col, TCOD_bkgnd_flag_t flag)
	{
		TCOD_console_set_back(console, x, y, col.data, flag);
	}
	
	/**
	 * This function modifies the foreground color of a cell, leaving other properties (background color and 
	 * ASCII code) unchanged.
	 */
	public void setForegroundColor(int x, int y, Color col)
	{
		TCOD_console_set_fore(console, x, y, col.data);
	}
	
	/**
	 * This function modifies the ASCII code of a cell, leaving other properties (background and foreground colors) 
	 * unchanged.
	 * Note that since a clear console has both background and foreground colors set to black for every cell, 
	 * using setChar will produce black characters on black background. Use putChar instead.
	 */
	public void setChar(int x, int y, int c)
	{
		TCOD_console_set_char(console, x, y, c);
	}
	
	/**
	 * This function draws a left aligned string on the console, using default foreground and background colors. 
	 * If the string reaches the right border of the console, it is truncated.
	 */
	public void printLeft(int x, int y, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		TCOD_console_print_left(console, x, y, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function draws a right aligned string on the console, using default foreground and background colors. 
	 * If the string reaches the left border of the console, it is truncated.
	 */
	public void printRight(int x, int y, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		TCOD_console_print_right(console, x, y, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function draws a centered string on the console, using default foreground and background colors. 
	 * If the string reaches borders of the console, it is truncated.
	 */
	public void printCenter(int x, int y, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		TCOD_console_print_center(console, x, y, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function draws a left aligned string in a rectangle inside the console, using default foreground and 
	 * background colors. If the string reaches the right border of the rectangle, carriage returns are inserted.
	 * If h > 0 and the bottom of the rectangle is reached, the string is truncated. If h = 0, the string is only 
	 * truncated if it reaches the bottom of the console.
	 * The function returns the height (number of console lines) of the printed string.
	 */
	public int printLeftRect(int x, int y, int w, int h, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		return TCOD_console_print_left_rect(console, x, y, w, h, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * Get the expected height without actually printing the string.
	 */
	public int getHeightLeftRect(int x, int y, int w, int h, string fmt, ...)
	{
		return TCOD_console_height_left_rect(console, x, y, w, h, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function draws a right aligned string in a rectangle inside the console, using default foreground and 
	 * background colors. If the string reaches the left border of the rectangle, carriage returns are inserted.
	 * If h > 0 and the bottom of the rectangle is reached, the string is truncated. If h = 0, the string is only 
	 * truncated if it reaches the bottom of the console.
	 * The function returns the height (number of console lines) of the printed string.
	 */
	public int printRightRect(int x, int y, int w, int h, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		return TCOD_console_print_right_rect(console, x, y, w, h, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * Get the expected height without actually printing the string.
	 */
	public int getHeightRightRect(int x, int y, int w, int h, string fmt, ...)
	{
		return TCOD_console_height_right_rect(console, x, y, w, h, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function draws a centered string in a rectangle inside the console, using default foreground and 
	 * background colors. If the string reaches the borders of the rectangle, carriage returns are inserted.
	 * If h > 0 and the bottom of the rectangle is reached, the string is truncated. If h = 0, the string is only 
	 * truncated if it reaches the bottom of the console.
	 * The function returns the height (number of console lines) of the printed string.
	 */
	public int printCenterRect(int x, int y, int w, int h, TCOD_bkgnd_flag_t flag, string fmt, ...)
	{
		return TCOD_console_print_center_rect(console, x, y, w, h, flag, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * Get the expected height without actually printing the string.
	 */
	public int getHeightCenterRect(int x, int y, int w, int h, string fmt, ...)
	{
		return TCOD_console_height_center_rect(console, x, y, w, h, std.string.toStringz(fmt), _arguments);
	}
	
	/**
	 * This function associates a background and a foreground color with a color control code.
	 */
	public static void setColorControl(ColorControl con, Color fore, Color back)
	{
		TCOD_console_set_color_control(con, fore.data, back.data);
	}
}
